<?php

declare(strict_types=1);
// +----------------------------------------------------------------------
// | swiftAdmin 极速开发框架 [基于WebMan开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
// +----------------------------------------------------------------------
// | swiftAdmin.net High Speed Development Framework
// +----------------------------------------------------------------------
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app\admin\controller;

use app\admin\controller\system\Material as SystemMaterial;
use Psr\SimpleCache\InvalidArgumentException;
use support\Response;
use think\db\exception\BindParamException;
use think\facade\Cache;
use think\facade\Db;
use Webman\Event\Event;
use system\Random;
use think\cache\driver\Memcached;
use think\cache\driver\Redis;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use app\AdminController;
use app\common\library\Email;
use app\common\library\Ftp;
use app\common\model\system\AdminNotice;
use app\common\model\system\Attachment;
use app\common\model\system\Config;
use app\common\model\system\User;
use app\common\model\system\Product;
use app\common\model\system\ProductLog;
use app\common\model\system\OrderProduct;
use app\common\model\system\UserGroup;
use app\common\model\system\UserThird;
use app\common\model\system\UserValidate;
use app\common\model\system\OrderMaterial;
use app\common\model\system\Material;
use app\common\model\system\MaterialPrice;

class Index extends AdminController
{

    /**
     * 初始化函数
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * @throws \Exception
     */
    public function index()
    {
        $notice_count = AdminNotice::where('status', 0)->count();
        return view('index/index', [
            'notice_count' => $notice_count,
        ]);
    }

    /**
     * 控制台首页
     * @return response
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws BindParamException
     */
    public function console()
    {
        if (request()->isAjax()) {
            // 获取数据
            $post = \request()->all();
            $page = (int)input('page') ?? 1;
            $limit = (int)input('limit') ?? 10;
            if (empty($post['type'])) {
                // 生成查询条件
                $where = array();
                $start = 0;
                $end = date('Ymd');
                if (!empty($post['title'])) {
                    $times = explode(' ~ ', $post['title']);
                    if (count($times) < 2) {
                        return $this->error('时间格式出错');
                    }
                    $start = $times[0] ?? 0;
                    $end = $times[1] ?? date('Ymd');
                }
                if (!empty($post['materialid'])) {
                    $where[] = ['id', '=', $post['materialid']];
                }
                $count = (new Material())->where($where)->count();
                $page = ($count <= $limit) ? 1 : $page;
                $list = (new Material())->where($where)
                    ->limit((int)$limit)->page((int)$page)
                    ->select();
                foreach ($list as $row) {
                    $materialprice = (new MaterialPrice())->where('materialid', $row['id'])
                        ->whereBetween('dates', [$start, $end])->group('materialid')
                        ->field('sum(weight) as mweight,sum(totals) as mtotals')->find();
                    $row['stock_weight'] = $materialprice['mweight'] ?? 0; //进货量
                    $row['stock_totals'] = $materialprice['mtotals'] ?? 0; //进货额
                    $row['stock_price'] = 0; //均价
                    if ($row['stock_weight'] > 0) {
                        $row['stock_price'] = floor($row['stock_totals'] * 100 / $row['stock_weight']) / 100;
                    }
                    $ordermaterial = (new OrderMaterial())->where('materialid', $row['id'])
                        ->whereBetween('ordersn', [$start, $end])->group('materialid')
                        ->field('sum(weights) as mweight')->find();
                    $row['out_weight'] = $ordermaterial['mweight'] ?? 0; //进货额
                }
                return $this->success('查询成功', "", $list, $count);
            } elseif ($post['type'] == 2) {
                // 生成查询条件
                $where = array();
                $start = 0;
                $end = time();
                if (!empty($post['titles'])) {
                    $times = explode(' ~ ', $post['titles']);
                    if (count($times) < 2) {
                        return $this->error('时间格式出错');
                    }
                    $start = strtotime($times[0]) ?? 0;
                    $end = strtotime($times[1]) ?? time();
                }
                if (!empty($post['products'])) {
                    $where[] = ['id', '=', $post['products']];
                }
                $startnumber = date('Ymd', $start);
                $endnumber = date('Ymd', $end);
                $count = (new Product())->where($where)->count();
                $page = ($count <= $limit) ? 1 : $page;
                $list = (new Product())->where($where)
                    ->limit((int)$limit)->page((int)$page)
                    ->select();
                foreach ($list as $row) {
                    $order = (new ProductLog())->where('goodsid', $row['id'])
                        ->where('money', '<', 0)
                        ->whereBetween('create_time', [$start, $end])->group('goodsid')
                        ->field('sum(money) as moneys')->find();
                    $order2 = (new ProductLog())->where('goodsid', $row['id'])
                        ->where('money', '>', 0)
                        ->whereBetween('create_time', [$start, $end])->group('goodsid')
                        ->field('sum(money) as moneys')->find();
                    $order3 = (new ProductLog())->where('goodsid', $row['id'])
                        ->where('type', 2)
                        ->whereBetween('create_time', [$start, $end])->group('goodsid')
                        ->field('sum(money) as moneys')->find();
                    //产品总重
                    $order3 = (new OrderProduct())->where('productid', $row['id'])
                        ->whereBetween('ordersn', [$startnumber, $endnumber])->group('productid')
                        ->field('sum(weights) as weightall,sum(guo) as guos')->find();
                    $row['ck'] = abs((int)($order['moneys'] ?? 0));
                    $row['rk'] = $order2['moneys'] ?? 0;
                    $row['rk2'] = $order3['moneys'] ?? 0;
                    $row['weightall'] = $order3['weightall'] ?? 0;
                    $row['guos'] = $order3['guos'] ?? 0;
                    //计算包数、
                    $row['yuji'] = 0;
                    $number = 0;
                    $str = trim(strtolower($row['spec'])) ?? ""; //大写转小写去掉俩端空格
                    if(strpos($str, "k")){
                        $number = (float)(substr_replace($str, "",strpos($str, "k")) ?? 0); //去掉指定字符串后内容并转浮点计算
                    }
                    if ($number > 0) {
                        $row['yuji'] = floor($row['weightall'] * 100 / $number) / 100;
                    }
                }
                return $this->success('查询成功', "", $list, $count);
            }
        }
        $data = [
            'stock_weight' => [], //进货重量前五
            'out_weight' => [], //出货重量前五
            'stock_totals' => [], //进货金额前五
        ];
        //进货量前5排名
        $data['stock_weight'] = (new MaterialPrice())->group('materialid')
            ->field('sum(weight) as mweight,materialid')
            ->order('mweight desc')
            ->limit(5)->select()->each(function ($item) {
                $item['materialtitle'] = (new Material())->where('id', $item['materialid'])->value('title');
                return $item;
            });
        //进货额前5排名
        $data['stock_totals'] = (new MaterialPrice())->group('materialid')
            ->field('sum(totals) as mtotals,materialid')
            ->order('mtotals desc')
            ->limit(5)->select()->each(function ($item) {
                $item['materialtitle'] = (new Material())->where('id', $item['materialid'])->value('title');
                return $item;
            });
        //出货量前5排名
        $data['out_weight'] = (new OrderMaterial())->group('materialid')
            ->field('sum(weights) as mweight,materialid')
            ->order('mweight desc')
            ->limit(5)->select()->each(function ($item) {
                $item['materialtitle'] = (new Material())->where('id', $item['materialid'])->value('title');
                return $item;
            });
        $data['materiallist'] = (new Material())->order("sku asc")->having('sku <= warn')->limit(5)->select();
        $data['productlist'] = (new Product())->order("stock asc")->limit(5)->select();
        $material = (new Material())->select();
        $product = (new Product())->select();
        return view('/index/console', ['data' => $data, 'material' => $material, 'product' => $product]);
    }

    /**
     * 获取数据结构
     * @param array $dataList
     * @param array $seriesList
     * @return array
     */
    protected function getEchartsData(array $dataList, array $seriesList): array
    {
        return [
            'color'   => ['#1890ff', '#ee6666', '#b0e689'],
            'tooltip' => ['trigger' => 'axis'],
            'legend'  => [
                'orient' => 'horizontal',
            ],
            'grid'    => [
                'left'   => '5%',
                'top'    => '13%',
                'bottom' => '15%',
                'right'  => '5%'
            ],
            'xAxis'   => [
                'type'        => 'category',
                'boundaryGap' => true,
                'data'        => $dataList,
            ],
            'yAxis'   => [
                'type' => 'value',
            ],
            'series'  => $seriesList
        ];
    }

    /**
     *
     * @param string $cycle
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    protected function getUserEcharts(string $cycle): array
    {
        $seriesList = [];
        $dataList = [];
        $condition = '%w';
        $dateBefore = date('Y-m-d', strtotime('-7 day'));
        $dateAfter = date('Y-m-d 23:59:59');
        switch ($cycle) {
            case 'week':
                $dataList = array('周日', '周一', '周二', '周三', '周四', '周五', '周六');
                break;
            case 'month':
                $condition = '%d';
                $dateBefore = date('Y-m-01');
                $dateAfter = date('Y-m-d', strtotime("+1 day"));
                $dataList = array(
                    '01' => ['1'], '02' => ['2'], '03' => ['3'], '04' => ['4'], '05' => ['5'], '06' => ['6'], '07' => ['7'], '08' => ['8'],
                    '09' => ['9'], '10' => ['10'], '11' => ['11'], '12' => ['12'], '13' => ['13'], '14' => ['14'], '15' => ['15'], '16' => ['16'],
                    '17' => ['17'], '18' => ['18'], '19' => ['19'], '20' => ['20'], '21' => ['21'], '22' => ['22'], '23' => ['23'], '24' => ['24'],
                    '25' => ['25'], '26' => ['26'], '27' => ['27'], '28' => ['28'], '29' => ['29'], '30' => ['30'], '31' => ['31']
                );
                break;
            case 'year':
                $condition = '%m';
                $dateBefore = date('Y-01-01');
                $dateAfter = date('Y-12-31 23:59:59');
                $dataList = array(
                    '01' => ['一月'], '02' => ['二月'], '03' => ['三月'], '04' => ['四月'], '05' => ['五月'], '06' => ['六月'],
                    '07' => ['七月'], '08' => ['八月'], '09' => ['九月'], '10' => ['十月'], '11' => ['十一月'], '12' => ['十二月']
                );
                break;
            default:
                break;
        }

        $resultList = $this->getCycleEcharts($dateBefore, $dateAfter, $condition);
        foreach ($resultList as $index => $item) {
            $tempList = [];

            foreach ($dataList as $key => $value) {
                $data = list_search($item, ['day' => $key]);
                if (!empty($data)) {
                    $tempList[$key] = $data;
                } else {
                    $tempList[$key] = ['day' => $value, 'count' => 0];
                }
            }

            $seriesList[] = [
                'name'       => $index,
                'type'       => 'line',
                'stack'      => 'Total',
                'showSymbol' => false,
                'itemStyle'  => ['normal' => ['areaStyle' => ['type' => 'default']]],
                'data'       => array_column($tempList, 'count'),
            ];
        }

        return [$dataList, $seriesList];
    }

    /**
     * 获取一段时间内订单列表
     * @param $dateBefore
     * @param $dateAfter
     * @param $condition
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    protected function getCycleEcharts($dateBefore, $dateAfter, $condition): array
    {
        $resultList = [];
        $columns = ['用户注册' => 'create_time', '用户登录' => 'login_time', '邀请注册' => 'invite_id'];
        foreach ($columns as $index => $field) {
            $time = str_replace('invite_id', 'create_time', $field);
            $resultList[$index] = \app\common\model\system\User::where($time, 'between time', [$dateBefore, $dateAfter])
                ->when($condition, function ($query) use ($condition, $time, $field) {
                    $query->field("FROM_UNIXTIME($time, '$condition') as day,count(*) as count");
                    if ($field == 'invite_id') {
                        $query->where('invite_id', '<>', 0);
                    }
                    $query->group("FROM_UNIXTIME($time, '$condition')");
                })->order($time, 'asc')->select()->toArray();
        }

        return $resultList;
    }

    /**
     * 分析页
     * @return mixed
     */
    public function analysis(): Response
    {
        return view('/index/analysis');
    }

    /**
     * 监控页
     * @return mixed
     */
    public function monitor(): Response
    {
        return view('/index/monitor');
    }

    /**
     * 获取系统配置
     * @return Response
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function basecfg(): Response
    {
        $config = Config::all();
        $config['fsockopen'] = function_exists('fsockopen');
        $config['stream_socket_client'] = function_exists('stream_socket_client');
        return view('/index/basecfg', ['config' => $config]);
    }

    /**
     * 编辑系统配置
     *
     * @return Response
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws InvalidArgumentException
     */
    public function baseSet(): Response
    {
        if (request()->isPost()) {
            $config = [];
            $post = request()->all();
            $list = Config::select()->toArray();
            foreach ($list as $key => $value) {
                $name = $value['name'];
                if (isset($post[$name])) {
                    $option['id'] = $value['id'];
                    if ('array' == trim($value['type'])) {
                        $option['value'] = json_encode($post[$name], JSON_UNESCAPED_UNICODE);
                    } else {
                        $option['value'] = $post[$name];
                    }

                    $config[$key] = $option;
                }
            }

            try {
                (new Config())->saveAll($config);
                $env = base_path() . '/.env';
                $parse = parse_ini_file($env, true);
                $parse['CACHE_DRIVER'] = $post['cache_type'];
                $parse['CACHE_HOSTNAME'] = $post['cache_host'];
                $parse['CACHE_HOSTPORT'] = $post['cache_port'];
                $parse['CACHE_SELECT'] = $post['cache_select'];
                $parse['CACHE_USERNAME'] = $post['cache_user'];
                $parse['CACHE_PASSWORD'] = $post['cache_pass'];
                write_file($env, parse_array_ini($parse));
            } catch (\Throwable $th) {
                return $this->error($th->getMessage());
            }

            // 清理系统核心缓存
            Cache::tag('core_system')->clear();
            $configList = Cache::get('config_list');
            foreach ($configList as $item) {
                Cache::delete($item);
            }
        }

        return $this->success('保存成功!');
    }

    /**
     * FTP测试上传
     */
    public function testFtp(): Response
    {
        if (request()->isPost()) {
            if (Ftp::instance()->ftpTest(request()->post())) {
                return $this->success('上传测试成功！');
            }
        }

        return $this->error('上传测试失败！');
    }

    /**
     * 邮件测试
     */
    public function testEmail()
    {
        if (request()->isPost()) {
            $info = Email::instance()->testEMail(request()->post());
            return $info === true ? $this->success('测试邮件发送成功！') : $this->error($info);
        }
    }

    /**
     * 缓存测试
     */
    public function testCache()
    {
        if (request()->isPost()) {

            $param = request()->post();
            if (!isset($param['type']) || empty($param['host']) || empty($param['port'])) {
                return $this->error('参数错误!');
            }

            $options = [
                'host'     => $param['host'],
                'port'     => (int)$param['port'],
                'username' => $param['user'],
                'password' => $param['pass']
            ];

            try {
                if (strtolower($param['type']) == 'redis') {
                    $drive = new Redis($options);
                } else {
                    $drive = new Memcached($options);
                }
            } catch (\Throwable $th) {
                return $this->error($th->getMessage());
            }

            if ($drive->set('test', 'cacheOK', 1000)) {
                return $this->success('缓存测试成功！');
            } else {
                return $this->error('缓存测试失败！');
            }
        }

        return false;
    }
}
